package io.spring.sample.graphql.jpa;

import com.querydsl.core.types.Predicate;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.query.FluentQuery;

import java.util.List;
import java.util.function.Function;


//@NoRepositoryBean指明当前接口不是我们领域类的接口（如PersonRepository）
/**
若UnitRepository extends QuerydslNcExecutor<Unit>,就算@EnableJpaRepositories(repositoryFactoryBeanClass没有设置也不会报错的！
感觉是纯粹动态的：repositoryFactoryBeanClass不设置,就会导致findBy()实际运行进入未自定制改造之前的流程，还会执行count()语句的，没有报错；
所以:只有配置EnableJpaRepositories(的才会真正的让findBy()进入我这自定义的代码中，才能省掉count()语句。
* */
@NoRepositoryBean
public interface QuerydslNcExecutor<T> extends QuerydslPredicateExecutor<T> {
    //不需要做count(*)统计，比缺省的findAll()提高性能百倍。
    /*
    下面findBy就能替换这个功能: 把pageable放入参数：()->{.page()}函数中。
    * */
  //  Page<T> findAllNc(Predicate predicate, Pageable pageable);
    //? 旧的说法 ?无法直接利用findAll这个接口名称的，只能另外自定义findAllNc。

    /*不修改采用基类方案：最差，会做count(*)统计，1+N条查询，全部字段的：#还有一种什么接口函数都不要自己写的完全交给底层spring-graphql做：没有分页，过滤受约束，全部字段的,没count,有Left Join；
    限制来自spring-data-commons/org/springframework/data/repository/query/FluentQuery.java:155 Page<T> page(Pageable pageable)必须Page<T>类型;
    追踪 spring-data-jpa/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicate.java:171 看来只能readPage()这里修改;
    最后决定在 FetchableFluentQueryByPredicate 的216行这个 Page<R> readPage(Pageable pageable) 特别定制。
    基类# 旧的是 <S extends T, R> R findBy（）;  S是实体T扩展子类型
    R 是返回类型 投影
    * */
    //<S extends T, R> R findBy(Predicate predicate, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction);

    /**支持单层interface投影; 直接根据resultType类型所有的字段生成查询全部字段，不支持第二层的的字段过滤性质投影查询，只能全部查。
    * */
    <S extends T, R, I> R findBy(Class<I> pifType,Predicate predicate, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction);
    /**直接上字符串模式的投影：支持第二层的的字段
     * */
    <S extends T, R> R findBy(List<String> fileds,Predicate predicate, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction);
    /**支持两层嵌套关联的投影，不支持3层或更多层次的。
     * 这里查询结果，若是能上Unit实体类的，虽然查到的并不是全部的字段都有数据。但是并不影响把这些对象实例直接用于JPA其它的操作，底层会自动查询所有的最新字段数据的。
     * */
    <S extends T, R> R findBy(QBeanMy<?> pathSel, Predicate predicate, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction);
}

